<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Kafka监听管理</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background: linear-gradient(135deg, #cce5ff 0%, #66b3ff 100%);
            min-height: 100vh;
            font-size: 16px;
            line-height: 1.6;
        }
        .container {
            background-color: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 5px 25px rgba(0,0,0,0.1);
            margin-bottom: 30px;
            transition: transform 0.3s ease, box-shadow 0.3s ease;
        }
        .container:hover {
            transform: translateY(-5px);
            box-shadow: 0 8px 30px rgba(0,0,0,0.15);
        }
        h1 {
            text-align: center;
            color: #2c3e50;
            margin-bottom: 10px;
            font-size: 2.5em;
            font-weight: 300;
            text-shadow: 1px 1px 2px rgba(0,0,0,0.1);
        }
        .subtitle {
            text-align: center;
            color: #7f8c8d;
            margin-bottom: 30px;
            font-size: 1.1em;
        }
        h2 {
            color: #3498db;
            border-bottom: 2px solid #ecf0f1;
            padding-bottom: 15px;
            margin-top: 0;
            font-weight: 500;
            font-size: 1.5em;
        }
        .form-group {
            margin-bottom: 20px;
        }
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: #2c3e50;
        }
        input[type="text"] {
            width: 100%;
            padding: 12px 15px;
            border: 1px solid #bdc3c7;
            border-radius: 6px;
            box-sizing: border-box;
            font-size: 16px;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        input[type="text"]:focus {
            outline: none;
            border-color: #3498db;
            box-shadow: 0 0 8px rgba(52, 152, 219, 0.3);
        }
        .btn {
            background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
            color: white;
            padding: 12px 25px;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            font-size: 16px;
            font-weight: 600;
            transition: all 0.3s ease;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        .btn:hover {
            background: linear-gradient(135deg, #2980b9 0%, #2573a7 100%);
            transform: translateY(-2px);
            box-shadow: 0 4px 15px rgba(0,0,0,0.2);
        }
        .btn:active {
            transform: translateY(0);
        }
        .btn.stop {
            background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);
        }
        .btn.stop:hover {
            background: linear-gradient(135deg, #c0392b 0%, #a93226 100%);
        }
        .btn.status {
            background: linear-gradient(135deg, #2ecc71 0%, #27ae60 100%);
        }
        .btn.status:hover {
            background: linear-gradient(135deg, #27ae60 0%, #229954 100%);
        }
        .btn:disabled {
            background: linear-gradient(135deg, #95a5a6 0%, #7f8c8d 100%);
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }
        .result {
            margin-top: 20px;
            padding: 15px;
            border-radius: 6px;
            display: none;
            animation: fadeIn 0.3s ease;
        }
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(-10px); }
            to { opacity: 1; transform: translateY(0); }
        }
        .result.success {
            background-color: #d4edda;
            color: #155724;
            border: 1px solid #c3e6cb;
        }
        .result.error {
            background-color: #f8d7da;
            color: #721c24;
            border: 1px solid #f5c6cb;
        }
        #statusResult {
            display: block;
        }
        pre {
            background-color: #f8f9fa;
            border: 1px solid #e9ecef;
            border-radius: 6px;
            padding: 15px;
            white-space: pre-wrap;
            word-wrap: break-word;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 20px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.05);
            border-radius: 8px;
            overflow: hidden;
        }
        th, td {
            padding: 15px;
            text-align: left;
            border-bottom: 1px solid #ecf0f1;
        }
        th {
            background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
            color: white;
            font-weight: 600;
            text-transform: uppercase;
            font-size: 0.9em;
            letter-spacing: 0.5px;
        }
        tr:nth-child(even) {
            background-color: #f8f9fa;
        }
        tr:hover {
            background-color: #e3f2fd;
        }
        .stop-btn {
            background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);
            color: white;
            padding: 8px 15px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 600;
            transition: all 0.3s ease;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }
        .stop-btn:hover {
            background: linear-gradient(135deg, #c0392b 0%, #a93226 100%);
            transform: translateY(-2px);
            box-shadow: 0 4px 10px rgba(0,0,0,0.2);
        }
        .stop-btn:disabled {
            background: linear-gradient(135deg, #95a5a6 0%, #7f8c8d 100%);
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }
        .no-data {
            text-align: center;
            padding: 30px;
            color: #7f8c8d;
            font-style: italic;
        }
        .status-active {
            color: #27ae60;
            font-weight: 600;
        }
        .status-inactive {
            color: #e74c3c;
            font-weight: 600;
        }
        .connection-status {
            margin-top: 10px;
            padding: 10px;
            border-radius: 4px;
            display: none;
            font-weight: 500;
        }
        .connection-success {
            background-color: #d4edda;
            color: #155724;
            border: 1px solid #c3e6cb;
            display: block;
        }
        .connection-error {
            background-color: #f8d7da;
            color: #721c24;
            border: 1px solid #f5c6cb;
            display: block;
        }
        footer {
            text-align: center;
            margin-top: 30px;
            color: #ecf0f1;
            font-size: 0.9em;
        }
    </style>
</head>
<body>
    <h1>Kafka监听管理</h1>
    <p class="subtitle">管理和监控Kafka集群的监听状态</p>
    
    <!-- 开启监听和停止监听功能 -->
    <div class="container">
        <div style="display: flex; flex-wrap: wrap; gap: 30px;">
            <!-- 开启监听功能 -->
            <div style="flex: 1; min-width: 300px;">
                <h2>开启监听</h2>
                <form id="startForm">
                    <div class="form-group">
                        <label for="startBootstrapServers">Kafka集群地址:</label>
                        <div style="display: flex; gap: 10px;">
                            <input type="text" id="startBootstrapServers" placeholder="例如: 192.168.31.203:9092" required style="flex: 1;">
                            <button type="button" class="btn" id="startTestConnectionBtn" style="white-space: nowrap;">检测连接</button>
                        </div>
                        <div id="startConnectionStatus" class="connection-status"></div>
                    </div>
                    <div class="form-group">
                        <label for="startTopic">Topic名称:</label>
                        <input type="text" id="startTopic" placeholder="例如: test-topic" required>
                    </div>
                    <div class="form-group">
                        <label for="startGroupId">消费组ID (可选):</label>
                        <input type="text" id="startGroupId" placeholder="例如: my-consumer-group">
                    </div>
                    <button type="submit" class="btn">开启监听</button>
                </form>
                <div id="startResult" class="result"></div>
            </div>
            
            <!-- 停止监听功能 -->
            <div style="flex: 1; min-width: 300px;">
                <h2>停止监听</h2>
                <form id="stopForm">
                    <div class="form-group">
                        <label for="stopBootstrapServers">Kafka集群地址:</label>
                        <div style="display: flex; gap: 10px;">
                            <input type="text" id="stopBootstrapServers" placeholder="例如: 192.168.31.203:9092" required style="flex: 1;">
                            <button type="button" class="btn" id="stopTestConnectionBtn" style="white-space: nowrap;">检测连接</button>
                        </div>
                        <div id="stopConnectionStatus" class="connection-status"></div>
                    </div>
                    <div class="form-group">
                        <label for="stopTopic">Topic名称:</label>
                        <input type="text" id="stopTopic" placeholder="例如: test-topic" required>
                    </div>
                    <div class="form-group">
                        <label for="stopGroupId">消费组ID (可选):</label>
                        <input type="text" id="stopGroupId" placeholder="例如: my-consumer-group">
                    </div>
                    <div class="form-group">
                        <label for="stopUniqueId">唯一标识 (可选，不填则停止所有相同参数的监听):</label>
                        <input type="text" id="stopUniqueId" placeholder="例如: a1b2c3d4">
                    </div>
                    <button type="submit" class="btn stop">停止监听</button>
                </form>
                <div id="stopResult" class="result"></div>
            </div>
        </div>
    </div>
    
    <!-- 获取监听状态功能 -->
    <div class="container">
        <h2>获取监听状态</h2>
        <button id="statusButton" class="btn status">获取当前监听状态</button>
        <div id="statusResult" class="result">
            <h3>监听状态:</h3>
            <table id="statusTable">
                <thead>
                    <tr>
                        <th>集群地址</th>
                        <th>Topic名称</th>
                        <th>消费组ID</th>
                        <th>唯一标识</th>
                        <th>状态</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody id="statusTableBody">
                    <tr>
                        <td colspan="6" class="no-data">点击上方按钮获取监听状态</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
    
    <!-- 发送消息功能 -->
    <div class="container">
        <h2>发送消息</h2>
        <form id="sendForm">
            <div class="form-group">
                <label for="sendBootstrapServers">Kafka集群地址:</label>
                <div style="display: flex; gap: 10px;">
                    <input type="text" id="sendBootstrapServers" placeholder="例如: 192.168.31.203:9092" required style="flex: 1;">
                    <button type="button" class="btn" id="sendTestConnectionBtn" style="white-space: nowrap;">检测连接</button>
                </div>
                <div id="sendConnectionStatus" class="connection-status"></div>
            </div>
            <div class="form-group">
                <label for="sendTopic">Topic名称:</label>
                <input type="text" id="sendTopic" placeholder="例如: test-topic" required>
            </div>
            <div class="form-group">
                <label for="sendMessage">消息内容:</label>
                <textarea id="sendMessage" rows="4" style="width: 100%; padding: 12px 15px; border: 1px solid #bdc3c7; border-radius: 6px; box-sizing: border-box; font-size: 16px; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;" placeholder="请输入要发送的消息内容" required></textarea>
            </div>
            <div class="form-group">
                <label for="sendGroupId">消费组ID (可选):</label>
                <input type="text" id="sendGroupId" placeholder="例如: my-consumer-group">
            </div>
            <button type="submit" class="btn">发送消息</button>
        </form>
        <div id="sendResult" class="result"></div>
    </div>
    
    <footer>
        <p>Kafka监听管理工具 &copy; 2025</p>
    </footer>

    <script>
        // 开启监听 - 连接检测
        document.getElementById('startTestConnectionBtn').addEventListener('click', function() {
            testConnection('start');
        });
        
        // 停止监听 - 连接检测
        document.getElementById('stopTestConnectionBtn').addEventListener('click', function() {
            testConnection('stop');
        });
        
        // 发送消息 - 连接检测
        document.getElementById('sendTestConnectionBtn').addEventListener('click', function() {
            testConnection('send');
        });
        
        // 通用连接检测函数
        function testConnection(formType) {
            const bootstrapServers = document.getElementById(formType + 'BootstrapServers').value.trim();
            
            if (!bootstrapServers) {
                showConnectionStatus(formType, '请输入Kafka集群地址', false);
                return;
            }
            
            // 禁用检测按钮并更改文本
            const testButton = document.getElementById(formType + 'TestConnectionBtn');
            testButton.disabled = true;
            testButton.textContent = '检测中...';
            
            // 显示正在检测的状态
            showConnectionStatus(formType, '正在检测连接...', true);
            
            // 发送连接检测请求，设置5秒超时
            Promise.race([
                fetch('/api/kafka/test-connection', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({ bootstrapServers: bootstrapServers })
                }),
                new Promise((_, reject) =>
                    setTimeout(() => reject(new Error('请求超时')), 5000)
                )
            ])
            .then(response => {
                if (response.ok) {
                    return response.text();
                } else {
                    throw new Error('网络错误: ' + response.status);
                }
            })
            .then(data => {
                if (data === 'success') {
                    showConnectionStatus(formType, '连接成功', true);
                } else {
                    showConnectionStatus(formType, data, false);
                }
            })
            .catch(error => {
                showConnectionStatus(formType, '检测失败: ' + error.message, false);
            })
            .finally(() => {
                // 恢复按钮状态
                testButton.disabled = false;
                testButton.textContent = '检测连接';
            });
        }
        
        // 显示连接状态
        function showConnectionStatus(formType, message, isSuccess) {
            const statusElement = document.getElementById(formType + 'ConnectionStatus');
            statusElement.textContent = message;
            statusElement.className = 'connection-status ' + (isSuccess ? 'connection-success' : 'connection-error');
        }
        
        // 开启监听
        document.getElementById('startForm').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const bootstrapServers = document.getElementById('startBootstrapServers').value.trim();
            const topic = document.getElementById('startTopic').value.trim();
            const groupId = document.getElementById('startGroupId').value.trim();
            
            const requestData = {
                bootstrapServers: bootstrapServers,
                topic: topic
            };
            
            if (groupId) {
                requestData.groupId = groupId;
            }
            
            fetch('/api/kafka/listen/start', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(requestData)
            })
            .then(response => response.text())
            .then(data => {
                showResult('startResult', data, true);
                // 自动刷新获取监听状态列表
                setTimeout(() => {
                    document.getElementById('statusButton').click();
                }, 1000);
            })
            .catch(error => {
                showResult('startResult', '请求失败: ' + error.message, false);
            });
        });
        
        // 停止监听
        document.getElementById('stopForm').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const bootstrapServers = document.getElementById('stopBootstrapServers').value.trim();
            const topic = document.getElementById('stopTopic').value.trim();
            const groupId = document.getElementById('stopGroupId').value.trim();
            const uniqueId = document.getElementById('stopUniqueId').value.trim();
            
            const requestData = {
                bootstrapServers: bootstrapServers,
                topic: topic
            };
            
            if (groupId) {
                requestData.groupId = groupId;
            }
            
            // 如果提供了唯一标识，则添加到请求中
            if (uniqueId) {
                requestData.uniqueId = uniqueId;
            }
            
            fetch('/api/kafka/listen/stop', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(requestData)
            })
            .then(response => response.text())
            .then(data => {
                showResult('stopResult', data, true);
                // 自动刷新获取监听状态列表
                setTimeout(() => {
                    document.getElementById('statusButton').click();
                }, 1000);
            })
            .catch(error => {
                showResult('stopResult', '请求失败: ' + error.message, false);
            });
        });
        
        // 获取监听状态
        document.getElementById('statusButton').addEventListener('click', function() {
            fetch('/api/kafka/listen/status', {
                method: 'GET',
                headers: {
                    'Content-Type': 'application/json'
                }
            })
            .then(response => response.json())
            .then(data => {
                displayStatus(data);
            })
            .catch(error => {
                document.getElementById('statusTableBody').innerHTML = 
                    '<tr><td colspan="5" class="no-data">获取状态失败: ' + error.message + '</td></tr>';
            });
        });
        
        // 发送消息
        document.getElementById('sendForm').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const bootstrapServers = document.getElementById('sendBootstrapServers').value.trim();
            const topic = document.getElementById('sendTopic').value.trim();
            const message = document.getElementById('sendMessage').value.trim();
            const groupId = document.getElementById('sendGroupId').value.trim();
            
            // 禁用发送按钮并更改文本
            const sendButton = document.getElementById('sendForm').querySelector('button[type="submit"]');
            sendButton.disabled = true;
            sendButton.textContent = '发送中...';
            
            const requestData = {
                bootstrapServers: bootstrapServers,
                topic: topic,
                message: message
            };
            
            if (groupId) {
                requestData.groupId = groupId;
            }
            
            fetch('/api/kafka/send', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(requestData)
            })
            .then(response => {
                // 检查响应状态
                if (!response.ok) {
                    // 如果响应不是2xx，抛出错误
                    return response.text().then(text => {
                        throw new Error(text || '未知错误');
                    });
                }
                return response.text();
            })
            .then(data => {
                showResult('sendResult', data, true);
                // 3秒后自动隐藏结果
                setTimeout(() => {
                    document.getElementById('sendResult').style.display = 'none';
                }, 3000);
            })
            .catch(error => {
                showResult('sendResult', '请求失败: ' + error.message, false);
                // 3秒后自动隐藏结果
                setTimeout(() => {
                    document.getElementById('sendResult').style.display = 'none';
                }, 3000);
            })
            .finally(() => {
                // 恢复按钮状态
                sendButton.disabled = false;
                sendButton.textContent = '发送消息';
            });
        });
        
        // 显示监听状态
        function displayStatus(statusData) {
            const tableBody = document.getElementById('statusTableBody');
            
            // 清空现有内容
            tableBody.innerHTML = '';
            
            // 如果没有数据
            if (Object.keys(statusData).length === 0) {
                tableBody.innerHTML = '<tr><td colspan="6" class="no-data">暂无监听数据</td></tr>';
                return;
            }
            
            // 用于存储相同参数组合的行索引
            const groupMap = new Map();
            
            // 先解析所有数据并按参数分组
            const rowData = [];
            for (const key in statusData) {
                if (statusData.hasOwnProperty(key)) {
                    // 解析key，格式为 "集群地址%topic名称%消费组ID%唯一ID"
                    const parts = key.split('%');
                    const bootstrapServers = parts[0];
                    const topic = parts[1];
                    const groupId = parts[2] || '默认消费组';
                    const uniqueId = parts[3] || '';
                    
                    const status = statusData[key] ? '监听中' : '未监听';
                    const statusClass = statusData[key] ? 'status-active' : 'status-inactive';
                    
                    // 创建分组键
                    const groupKey = `${bootstrapServers}%${topic}%${groupId}`;
                    
                    rowData.push({
                        bootstrapServers,
                        topic,
                        groupId,
                        uniqueId,
                        status,
                        statusClass,
                        groupKey
                    });
                    
                    // 将行索引添加到对应的组中
                    if (!groupMap.has(groupKey)) {
                        groupMap.set(groupKey, []);
                    }
                    groupMap.get(groupKey).push(rowData.length - 1);
                }
            }
            
            // 定义一组背景色用于区分不同组
            const backgroundColors = [
                '#e3f2fd', '#e8f5e9', '#fff3e0', '#fce4ec', '#f3e5f5',
                '#e0f7fa', '#f1f8e9', '#fff8e1', '#ffebee', '#fafafa'
            ];
            
            // 遍历分组并添加到表格中
            let colorIndex = 0;
            groupMap.forEach((indices, groupKey) => {
                const backgroundColor = indices.length > 1 ? backgroundColors[colorIndex % backgroundColors.length] : '';
                if (indices.length > 1) {
                    colorIndex++;
                }
                
                indices.forEach(index => {
                    const data = rowData[index];
                    const row = document.createElement('tr');
                    
                    // 如果该组有多个元素，则设置背景色
                    if (backgroundColor) {
                        row.style.backgroundColor = backgroundColor;
                    }
                    
                    row.innerHTML = `
                        <td>${data.bootstrapServers}</td>
                        <td>${data.topic}</td>
                        <td>${data.groupId}</td>
                        <td>${data.uniqueId}</td>
                        <td class="${data.statusClass}">${data.status}</td>
                        <td>
                            <button class="stop-btn" onclick="stopListener(this, '${data.bootstrapServers}', '${data.topic}', '${data.groupId}', '${data.uniqueId}')">停止监听</button>
                        </td>
                    `;
                    
                    tableBody.appendChild(row);
                });
            });
        }
        
        // 停止监听函数
        function stopListener(button, bootstrapServers, topic, groupId, uniqueId) {
            // 禁用按钮并更改文本
            button.disabled = true;
            button.textContent = '执行中...';
            
            const requestData = {
                bootstrapServers: bootstrapServers,
                topic: topic,
                uniqueId: uniqueId
            };
            
            if (groupId && groupId !== '默认消费组') {
                requestData.groupId = groupId;
            }
            
            fetch('/api/kafka/listen/stop', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(requestData)
            })
            .then(response => response.text())
            .then(data => {
                alert(data);
                // 重新获取状态
                document.getElementById('statusButton').click();
                // 请求成功后保持按钮禁用状态，直到列表刷新完成
            })
            .catch(error => {
                alert('请求失败: ' + error.message);
                // 恢复按钮状态
                button.disabled = false;
                button.textContent = '停止监听';
            });
        }
        
        // 显示结果
        function showResult(elementId, message, isSuccess) {
            const resultElement = document.getElementById(elementId);
            resultElement.textContent = message;
            resultElement.className = 'result ' + (isSuccess ? 'success' : 'error');
            resultElement.style.display = 'block';
        }
    </script>
</body>
</html>